/*  Game/Army Editor for yALB - Yet Another List Builder (roster Editor for Wargames/tabletop games).
    Copyright (C) 2008-2012  Daniel Ricardo Castro Alvarado

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.*/


#include "structwriter.h"
#include "other/objectactions.h"

#include <QStringList>
#include <QFile>
#include <QSet>
#include <QHash>


StructWriter::StructWriter(QXmlStreamWriter &writer)
{
    this->writer = &writer;
}

void StructWriter::writeFileInformation(const FileInformation &information) {
    writer->writeStartElement("information");
    if(!information.name.isEmpty())
        writer->writeTextElement("name", information.name);
    if(!information.creator.isEmpty())
        writer->writeTextElement("creator", information.creator);
    if(!information.version.isEmpty())
        writer->writeTextElement("version", information.version);
    if(!information.website.isEmpty())
        writer->writeTextElement("website", information.website);
    if(!information.comments.isEmpty())
        writer->writeTextElement("comments", information.comments);
    writer->writeEndElement();
}

void StructWriter::writeUnitCategory(const GameCategory &category, const QString& key) {
    writer->writeStartElement("unit_category");
    writer->writeTextElement("name", category.getName());
    writer->writeTextElement("key", key);
    writer->writeTextElement("numeric_limit", QString::number(category.getNumericLimit()));
    writer->writeTextElement("point_limit", QString::number(category.getPointLimit()));
    writer->writeTextElement("percentage_limit", QString::number(category.getPercentageLimit()));
    writer->writeEndElement();
}

void StructWriter::writeUnitCategories(const QVector<KeyPair<GameCategory> > &categories) {
    for(int i = 0; i<categories.count(); ++i) {
        const KeyPair<GameCategory> &pair = categories.at(i);
        writeUnitCategory(pair.value, pair.key);
    }
}

void StructWriter::writeItemCategory(const GameCategory &category, const QString& key) {
    writer->writeStartElement("item_category");
    writer->writeTextElement("name", category.getName());
    writer->writeTextElement("key", key);
    writer->writeTextElement("numeric_limit", QString::number(category.getNumericLimit()));
    writer->writeTextElement("point_limit", QString::number(category.getPointLimit()));
    writer->writeTextElement("percentage_limit", QString::number(category.getPercentageLimit()));
    writer->writeEndElement();
}

void StructWriter::writeItemCategories(const QVector<KeyPair<GameCategory> > &categories) {
    for(int i = 0; i<categories.count(); ++i) {
        const KeyPair<GameCategory> &pair = categories.at(i);
        writeItemCategory(pair.value, pair.key);
    }
}

void StructWriter::writeOptionCategory(const GameCategory &category, const QString& key) {
    writer->writeStartElement("option_category");
    writer->writeTextElement("name", category.getName());
    writer->writeTextElement("key", key);
    writer->writeTextElement("numeric_limit", QString::number(category.getNumericLimit()));
    writer->writeTextElement("point_limit", QString::number(category.getPointLimit()));
    writer->writeTextElement("percentage_limit", QString::number(category.getPercentageLimit()));
    writer->writeEndElement();
}

void StructWriter::writeOptionCategories(const QVector<KeyPair<GameCategory> > &categories) {
    for(int i = 0; i<categories.count(); ++i) {
        const KeyPair<GameCategory> &pair = categories.at(i);
        writeOptionCategory(pair.value, pair.key);
    }
}

void StructWriter::writeColumn(const Column &col, const QString& key) {
    writer->writeStartElement("column");
    writer->writeAttribute("visible", col.visible ? "yes" : "no");
    writer->writeTextElement("name", col.getName());
    writer->writeTextElement("default_value", col.defaultValue);
    writer->writeTextElement("default_value_mask", col.defaultValueAs);
    writer->writeTextElement("key", key);
    writer->writeEndElement();
}

void StructWriter::writeColumns(const QList<KeyPair<Column> > &columns) {
    for(int i = 0; i<columns.count(); ++i) {
        const KeyPair<Column> &pair = columns.at(i);
        writeColumn(pair.value, pair.key);
    }
}

void StructWriter::writeUnitProperty(const GameProperty &property, const QString& key) {
    writer->writeStartElement("unit_property");
    writer->writeTextElement("name", property.getName());
    writer->writeTextElement("default_value", property.defaultValue);
    writer->writeTextElement("key", key);
    writer->writeEndElement();
}

void StructWriter::writeUnitProperties(const QList<KeyPair<GameProperty> > &properties) {
    for(int i = 0; i<properties.count(); ++i) {
        const KeyPair<GameProperty> &pair = properties.at(i);
        writeUnitProperty(pair.value, pair.key);
    }
}

void StructWriter::writeItemProperty(const GameProperty &property, const QString& key) {
    writer->writeStartElement("item_property");
    writer->writeTextElement("name", property.getName());
    writer->writeTextElement("default_value", property.defaultValue);
    writer->writeTextElement("key", key);
    writer->writeEndElement();
}

void StructWriter::writeItemProperties(const QList<KeyPair<GameProperty> > &properties) {
    for(int i = 0; i<properties.count(); ++i) {
        const KeyPair<GameProperty> &pair = properties.at(i);
        writeItemProperty(pair.value, pair.key);
    }
}

void StructWriter::writeOptionProperty(const GameProperty &property, const QString& key) {
    writer->writeStartElement("option_property");
    writer->writeTextElement("name", property.getName());
    writer->writeTextElement("default_value", property.defaultValue);
    writer->writeTextElement("key", key);
    writer->writeEndElement();
}

void StructWriter::writeOptionProperties(const QList<KeyPair<GameProperty> > &properties) {
    for(int i = 0; i<properties.count(); ++i) {
        const KeyPair<GameProperty> &pair = properties.at(i);
        writeOptionProperty(pair.value, pair.key);
    }
}

void StructWriter::writeOption(const UnitOption &option, const QString& key) {
    writer->writeStartElement("option");
#ifdef UNIT_OPTION_INHERITED_KEY
    if(!option.inheritedKey.isEmpty())
        writer->writeAttribute("inherits", option.inheritedKey);
#endif
    writer->writeAttribute("category", option.category);
    writer->writeAttribute("initial_state", QString::number(option.state));
    writer->writeTextElement("name", option.getName());
    writer->writeTextElement("key", key);
    writer->writeTextElement("required", option.required);
    writer->writeTextElement("cost", QString::number(option.getCost(),'g', 2));
    writer->writeTextElement("cost_per_model", option.costPerMin ? "yes" : "no");

    writeActions(option.actions);

    writeProperties(option.properties);
    writer->writeEndElement();
}

void StructWriter::writeOptions(const QList<KeyPair<UnitOption> > &options) {
    for(int i = 0; i<options.count(); ++i) {
        const KeyPair<UnitOption> &pair = options.at(i);
        writeOption(pair.value, pair.key);
    }
}

void StructWriter::writeItem(const GameItem &item, const QString& key) {
    writer->writeStartElement("item");
    writer->writeAttribute("category", item.category);
    writer->writeTextElement("name", item.getName());
    writer->writeTextElement("key", key);
    writer->writeTextElement("cost", QString::number(item.getCost(),'g', 2));
    writer->writeTextElement("cost_per_model", item.costPerMin ? "yes" : "no");
    writer->writeTextElement("max_number", QString::number(item.getMaximumNumber()));

    writeActions(item.actions);
    writeProperties(item.properties);
    writer->writeEndElement();
}

void StructWriter::writeItems(const QVector<KeyPair<GameItem> > &items) {
    for(int i = 0; i<items.count(); ++i) {
        const KeyPair<GameItem> &pair = items.at(i);
        writeItem(pair.value, pair.key);
    }
}

void StructWriter::writeItemLimits(const QHash<QString, InheritedCategoryData> &limits) {
    writer->writeStartElement("item_limits");
    QHash<QString, InheritedCategoryData>::const_iterator i;
    for(i = limits.constBegin(); i != limits.constEnd(); ++i) {
        const InheritedCategoryData& e = i.value();
        writer->writeStartElement("element");
        writer->writeAttribute("key", i.key());
        writer->writeTextElement("numeric_limit", QString::number(e.numericLimit));
        writer->writeTextElement("percentage_limit", QString::number(e.percentageLimit));
        writer->writeTextElement("point_limit", QString::number(e.pointLimit));
        writer->writeEndElement();
    }
    writer->writeEndElement();
}

void StructWriter::writeUnit(const Unit &unit, const QString &key) {
    writer->writeStartElement("unit");
    writer->writeAttribute("category", unit.category);

    writer->writeTextElement("name", unit.getName());
    writer->writeTextElement("key", key);
    writer->writeTextElement("description", unit.description);
    writer->writeTextElement("flags", QString::number((int)unit.flags));
    writer->writeTextElement("minimum_size", QString::number(unit.getMinimumSize()));
    writer->writeTextElement("maximum_size", QString::number(unit.getMaximumSize()));
    writer->writeTextElement("cost", QString::number(unit.getCost(),'g', 2));
    writer->writeTextElement("allowed_items", unit.allowedItems.join(","));
    writeItemLimits(unit.itemLimits);
    writeCells(unit.cells);

    writer->writeStartElement("options");
    QStringList options = unit.options.keys();
    for(int i = 0; i<options.count(); ++i)
        writeOption(unit.options.get(options.at(i)), options.at(i));
    writer->writeEndElement();

    writeProperties(unit.properties);

    writer->writeEndElement();
}

void StructWriter::writeUnits(const QList<KeyPair<Unit> > &units) {
    for(int i = 0; i<units.count(); ++i) {
        const KeyPair<Unit> &pair = units.at(i);
        writeUnit(pair.value, pair.key);
    }
}

void StructWriter::writeGlobalText(const GlobalText &gText, const QString& key) {
    writer->writeStartElement("global_text");
    writer->writeTextElement("name", gText.getName());
    writer->writeTextElement("key", key);
    writer->writeTextElement("text", gText.text);
    writer->writeEndElement();
}

void StructWriter::writeGlobalTexts(const QList<KeyPair<GlobalText> > &texts) {
    for(int i = 0; i<texts.count(); ++i) {
        const KeyPair<GlobalText> &pair = texts.at(i);
        writeGlobalText(pair.value, pair.key);
    }
}

void StructWriter::writeInheritedUnitCategoryData(const QHash<QString, InheritedCategoryData> &data) {
    writer->writeStartElement("override_unit_categories");
    QHash<QString, InheritedCategoryData>::const_iterator i;
    for(i = data.constBegin(); i != data.constEnd(); ++i) {
        const InheritedCategoryData& e = i.value();
        writer->writeStartElement("element");
        writer->writeAttribute("key", i.key());
        writer->writeTextElement("numeric_limit", QString::number(e.numericLimit));
        writer->writeTextElement("percentage_limit", QString::number(e.percentageLimit));
        writer->writeTextElement("point_limit", QString::number(e.pointLimit));
        writer->writeEndElement();
    }
    writer->writeEndElement();
}

void StructWriter::writeInheritedItemCategoryData(const QHash<QString, InheritedCategoryData> &data) {
    writer->writeStartElement("override_item_categories");
    QHash<QString, InheritedCategoryData>::const_iterator i;
    for(i = data.constBegin(); i != data.constEnd(); ++i) {
        const InheritedCategoryData& e = i.value();
        writer->writeStartElement("element");
        writer->writeAttribute("key", i.key());
        writer->writeTextElement("numeric_limit", QString::number(e.numericLimit));
        writer->writeTextElement("percentage_limit", QString::number(e.percentageLimit));
        writer->writeTextElement("point_limit", QString::number(e.pointLimit));
        writer->writeEndElement();
    }
    writer->writeEndElement();
}

void StructWriter::writeInheritedOptionCategoryData(const QHash<QString, InheritedCategoryData> &data) {
    writer->writeStartElement("override_option_categories");
    QHash<QString, InheritedCategoryData>::const_iterator i;
    for(i = data.constBegin(); i != data.constEnd(); ++i) {
        const InheritedCategoryData& e = i.value();
        writer->writeStartElement("element");
        writer->writeAttribute("key", i.key());
        writer->writeTextElement("numeric_limit", QString::number(e.numericLimit));
        writer->writeTextElement("percentage_limit", QString::number(e.percentageLimit));
        writer->writeTextElement("point_limit", QString::number(e.pointLimit));
        writer->writeEndElement();
    }
    writer->writeEndElement();
}

void StructWriter::writeInheritedItemData(const QHash<QString, InheritedItemData> &data) {
    writer->writeStartElement("override_items");
    QHash<QString, InheritedItemData>::const_iterator i;
    for(i = data.constBegin(); i != data.constEnd(); ++i) {
        const InheritedItemData& e = i.value();

        writer->writeStartElement("element");
        writer->writeAttribute("key", i.key());
        writer->writeTextElement("cost", QString::number(e.cost,'g', 2));
        writer->writeTextElement("maximum_number", QString::number(e.maxNumber));
        writer->writeEndElement();
    }
    writer->writeEndElement();
}

void StructWriter::writeInheritedOptionData(const QHash<QString, InheritedOptionData> &data) {
    writer->writeStartElement("override_options");
    QHash<QString, InheritedOptionData>::const_iterator i;
    for(i = data.constBegin(); i != data.constEnd(); ++i) {
        const InheritedOptionData& e = i.value();

        writer->writeStartElement("element");
        writer->writeAttribute("key", i.key());
        writer->writeTextElement("cost", QString::number(e.cost,'g', 2));
        writer->writeEndElement();
    }
    writer->writeEndElement();
}

// Private

void StructWriter::writeActions(const Actions &actions) {
    writer->writeStartElement("actions");
    for(int i = 0; i<actions.size(); ++i) {
        writer->writeStartElement("action");
        writer->writeAttribute("type", QString::number(actions.at(i)->type()));
        actions.at(i)->writeToFile(writer);
        writer->writeEndElement();
    }
    writer->writeEndElement();
}

void StructWriter::writeProperties(const QHash<QString, QString>& properties) {
    writer->writeStartElement("properties");
    QHash<QString, QString>::const_iterator i;
    for(i = properties.constBegin(); i != properties.constEnd(); ++i) {
        writer->writeStartElement("value");
        writer->writeAttribute("key", i.key());
        writer->writeCharacters(i.value());
        writer->writeEndElement();
    }
    writer->writeEndElement();
}

void StructWriter::writeCells(const QHash<QString, QString>& cells) {
    writer->writeStartElement("cells");
    QHash<QString, QString>::const_iterator i;
    for(i = cells.constBegin(); i != cells.constEnd(); ++i) {
        writer->writeStartElement("value");
        writer->writeAttribute("key", i.key());
        writer->writeCharacters(i.value());
        writer->writeEndElement();
    }
    writer->writeEndElement();
}
